package org.bits.ui;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.*;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

import org.bits.common.ui.ItemListPanel;
import org.bits.data.*;
import org.bits.io.UserOptionsSerializer;
import org.bits.model.DataAccessModel;
import org.bits.ui.model.FieldValuesTableModel;
import org.jutils.ui.CardPanel;
import org.jutils.ui.event.ActionListenerList;
import org.jutils.ui.event.ItemActionListener;
import org.jutils.ui.model.ItemComboBoxModel;

/*******************************************************************************
 * 
 ******************************************************************************/
public class FilterView
{
    /**  */
    private JPanel filterPanel;
    /**  */
    private JComboBox filterField;
    /**  */
    private CardPanel resultsPanel;
    /**  */
    private FieldValuesTableModel<Finding> findingsModel;
    /**  */
    private ItemListPanel<Finding> findingsPanel;
    /**  */
    private FieldValuesTableModel<Issue> issuesModel;
    /**  */
    private ItemListPanel<Issue> issuesPanel;
    /**  */
    private ItemComboBoxModel<Filter<?>> filtersModel;
    /**  */
    private DataAccessModel dataModel;
    /**  */
    private ActionListenerList clearListeners;

    /***************************************************************************
     * @param dataModel
     * @param optionsSerializer
     **************************************************************************/
    public FilterView( DataAccessModel dataModel,
        UserOptionsSerializer optionsSerializer )
    {
        this.dataModel = dataModel;
        this.clearListeners = new ActionListenerList();

        resultsPanel = new CardPanel();
        findingsModel = new FieldValuesTableModel<Finding>();
        findingsPanel = new ItemListPanel<Finding>( findingsModel );
        issuesModel = new FieldValuesTableModel<Issue>();
        issuesPanel = new ItemListPanel<Issue>( issuesModel );

        resultsPanel.addCard( findingsPanel.getView() );
        resultsPanel.addCard( issuesPanel.getView() );
        findingsPanel.getTable().setAutoResizeMode(
            JTable.AUTO_RESIZE_NEXT_COLUMN );

        GridBagConstraints constraints;

        filterPanel = new JPanel( new GridBagLayout() );
        filtersModel = new ItemComboBoxModel<Filter<?>>();

        constraints = new GridBagConstraints( 0, 0, 1, 1, 1.0, 0.0,
            GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
            new Insets( 4, 4, 4, 4 ), 0, 0 );
        filterPanel.add( createFilterPanel(), constraints );

        constraints = new GridBagConstraints( 0, 1, 1, 1, 1.0, 1.0,
            GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets( 4,
                0, 0, 0 ), 0, 0 );
        filterPanel.add( resultsPanel.getView(), constraints );

        UserOptions options = optionsSerializer.getOptions();

        filtersModel.setItems( options.filters );

        if( !options.filters.isEmpty() )
        {
            filterField.setSelectedIndex( 0 );
            // displayFilter( options.filters.get( 0 ) );
        }
    }

    /***************************************************************************
     * @param l
     **************************************************************************/
    public void addFindingSelectedListener( ItemActionListener<Finding> l )
    {
        findingsPanel.addItemSelectedListener( l );
    }

    /***************************************************************************
     * @param l
     **************************************************************************/
    public void addEditFindingListener( ItemActionListener<Finding> l )
    {
        findingsPanel.addEditItemListener( l );
    }

    /***************************************************************************
     * @param l
     **************************************************************************/
    public void addClearListener( ActionListener l )
    {
        clearListeners.addListener( l );
    }

    /***************************************************************************
     * @param filter
     **************************************************************************/
    @SuppressWarnings( "unchecked")
    private void displayFilter( Filter<?> filter )
    {
        clearListeners.fireListeners( this, -1, null );

        switch( filter.getDataType() )
        {
            case FINDING:
                displayFindingFilter( ( Filter<Finding> )filter );
                break;

            case ISSUE:
                displayIssueFilter( ( Filter<Issue> )filter );
                break;

            case AUTHORIZATION:
                // TODO display the authorization filter.
                break;

            case TASK:
                // TODO display the authorization filter.
                break;
        }

    }

    /***************************************************************************
     * @param filter
     **************************************************************************/
    private void displayFindingFilter( Filter<Finding> filter )
    {
        List<Finding> findings;
        List<Field<Finding>> fields = filter.getDisplayFields();

        JTable table = findingsPanel.getTable();

        findingsModel.setFields( fields );
        setColumnWidths( table, new ArrayList<Field<?>>( fields ) );
        resultsPanel.showCard( findingsPanel.getView() );

        findings = dataModel.filterFindings( filter );

        if( findings != null )
        {
            findingsModel.setItems( findings );
        }
    }

    /***************************************************************************
     * @param filter
     **************************************************************************/
    private void displayIssueFilter( Filter<Issue> filter )
    {
        List<Issue> issues;
        List<Field<Issue>> fields = filter.getDisplayFields();

        JTable table = issuesPanel.getTable();

        issuesModel.setFields( fields );
        setColumnWidths( table, new ArrayList<Field<?>>( fields ) );
        resultsPanel.showCard( issuesPanel.getView() );

        issues = dataModel.filterIssues( filter );

        if( issues != null )
        {
            issuesModel.setItems( issues );
        }
    }

    /***************************************************************************
     * @param table
     * @param fields
     **************************************************************************/
    private void setColumnWidths( JTable table, List<Field<?>> fields )
    {
        TableColumnModel colModel = table.getColumnModel();

        for( int i = 0; i < fields.size(); i++ )
        {
            Field<?> field = fields.get( i );
            int width = field.getDefaultColumnWidth();

            if( width > 0 )
            {
                TableColumn col = colModel.getColumn( i );
                col.setPreferredWidth( width );
                col.setMinWidth( width );
                col.setMaxWidth( width );
            }
        }
    }

    /***************************************************************************
     * @return
     **************************************************************************/
    private Component createFilterPanel()
    {
        JPanel filterPanel = new JPanel( new GridBagLayout() );
        JLabel filterLabel = new JLabel( "Filter: " );
        filterField = new JComboBox( filtersModel );
        GridBagConstraints constraints;

        filterField.addActionListener( new FilterChangedListener() );

        constraints = new GridBagConstraints( 0, 0, 1, 1, 0.0, 0.0,
            GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
            new Insets( 0, 4, 0, 4 ), 0, 0 );
        filterPanel.add( filterLabel, constraints );

        constraints = new GridBagConstraints( 1, 0, 1, 1, 1.0, 0.0,
            GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets( 0,
                4, 0, 4 ), 0, 0 );
        filterPanel.add( filterField, constraints );

        return filterPanel;
    }

    /***************************************************************************
     * @return
     **************************************************************************/
    public Container getView()
    {
        return filterPanel;
    }

    /***************************************************************************
     * 
     **************************************************************************/
    private class FilterChangedListener implements ActionListener
    {
        @Override
        public void actionPerformed( ActionEvent e )
        {
            Filter<?> filter = filtersModel.getSelectedItem();
            displayFilter( filter );
        }
    }
}
